import { ref } from 'vue'
// 创建用户相关的小仓库
import { defineStore } from 'pinia'
// 引入接口
import { reqLogin, reqUserInfo, reqLogout } from '@/api/user/index'
// 引入操作本地存储的工具方法
import { GET_TOKEN, REMOVE_TOKEN, SET_TOKEN } from '@/utils/token'
// 引入路由(常量路由)
import { constantRoute, asyncRoute, anyRoute } from '@/router/routes'
import { loginFormDate } from '@/api/user/type'
// 获取路由器实例对象
import router from '@/router'
// 引入深拷贝方法
// @ts-ignore
import cloneDeep from 'lodash/cloneDeep'

// 创建用户小仓库  使用组合式API写法
const useUserStore = defineStore('User', () => {
  // 数据
  // 存储用户唯一标识token,从本地存储中进行获取
  // let token = ref(localStorage.getItem('TOKEN')||'')
  let token = ref(GET_TOKEN() || '')
  // 仓库存储生成菜单需要的数据(路由)
  let menuRoutes = ref(constantRoute)
  // 存储用户名字
  let userName = ref('')
  // 存储用户头像
  let userAvatar = ref('')
  // 存储用户角色
  let userRole = ref<string[]>([])
  // 存储用户的全部按钮名称
  let buttons = ref<string[]>([])

  // 用于过滤异步路由的方法
  function filterAsyncRoute(asyncRoute: any, routes: any) {
    return asyncRoute.filter((item: any) => {
      // 是否包含路由名
      if (routes.includes(item.name)) {
        // 过滤二级路由
        if (item.children && item.children.length > 0) {
          // 递归调用过滤二级路由
          item.children = filterAsyncRoute(item.children, routes)
        }
        // 存储到过滤后的数组中
        return true
      }
    })
  }
  // 用户登录方法 async异步函数会返回一个Promise对象状态由返回的结果决定
  async function userLogin(data: loginFormDate) {
    // 发送登录请求(已定义好在api/user/index.ts中)
    const result = await reqLogin(data) // await只接收成功返回的数据
    // 登录请求成功200：获取到token并存储
    if (result.code === 200) {
      // 由于pinia|vuex存储数据其实利用js对象,并非持久化,需要进行本地存储
      token.value = result.data as string
      // 本地持久化存储token,token用于每次获取用户的数据,每次发请求都需要携带
      // localStorage.setItem('TOKEN', token.value)
      // 将token本地存储进行封装到src/utils/token.ts中
      SET_TOKEN(token.value as string)
      // 保证当前async函数返回一个成功的promise对象
      return 'ok'
    } else {
      // 登录请求失败201：登录失败错误信息
      return Promise.reject(new Error(result.data))
    }
  }
  // 获取用户信息的方法
  async function userInfo() {
    // 获取用户的信息进行存储于仓库中
    let result = await reqUserInfo()
    // 如果获取用户信息成功,就存储用户信息
    if (result.code === 200) {
      userName.value = result.data.name
      userAvatar.value = result.data.avatar
      userRole.value = result.data.roles
      buttons.value = result.data.buttons
      // 调用过滤异步路由的方法，获取过滤后的异步路由
      const userAsyncRoute = filterAsyncRoute(
        cloneDeep(asyncRoute),
        result.data.routes,
      )
      // 获取当前用户的全部路由
      menuRoutes.value = [...constantRoute, ...userAsyncRoute, ...anyRoute]
      // 目前路由器管理的只有常量路由：用户计算完毕的异步路由和任意路由需要动态追加
      ;[...userAsyncRoute, ...anyRoute].forEach((route: any) => {
        // 为路由器动态追加路由
        router.addRoute(route)
      })
      return 'ok' // 返回一个成功的Promise对象
    } else {
      // 获取信息失败(用户信息不存在)
      return Promise.reject(new Error(result.message)) // 返回一个失败的Promise对象
    }
  }
  // 退出登录的方法
  async function userLogout() {
    // 通知服务器本地token失效
    const result = await reqLogout()
    if (result.code === 200) {
      // userName.value = ''
      // userAvatar.value = ''
      // token.value = ''
      // menuRoutes.value = constantRoute
      // token.value = ''
      REMOVE_TOKEN() // 清除本地token
      return 'ok'
    } else {
      // 返回一个失败的Promise
      Promise.reject(new Error(result.message))
    }
  }

  // 将存储的数据和方法进行暴露
  return {
    userLogin,
    userInfo,
    userLogout,
    token,
    menuRoutes,
    userName,
    userAvatar,
    userRole,
    buttons,
  }
})
// 对外暴露获取小仓库的方法
export default useUserStore
